home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / accounts / nls-lib.sha < prev    next >
Internet Message Format  |  1996-11-17  |  32KB

  1. From jfh@rpp386.cactus.org Sat Feb 26 14:35:22 EST 1994
  2. Article: 6007 of comp.os.linux.development
  3. Newsgroups: comp.os.linux.development
  4. Path: bigblue.oit.unc.edu!concert!news-feed-1.peachnet.edu!gatech!swrinde!cs.utexas.edu!chinacat!rpp386!jfh
  5. From: jfh@rpp386.cactus.org (John F. Haugh II)
  6. Subject: Alpha release of message catalog commands and functions
  7. Message-ID: <1994Feb26.052716.15677@rpp386>
  8. Sender: jfh@rpp386 (John F. Haugh II)
  9. Organization: River Parishes Programming, Austin TX
  10. Date: Sat, 26 Feb 1994 05:27:16 GMT
  11. Lines: 1257
  12.  
  13. I've been wanting to add National Language Support to Shadow for some
  14. time now but there is no freely redistributable NLS package that I am
  15. aware of.  I found some stuff in an old hacked up ELM directory, but
  16. it didn't look to be complete.  This isn't what I'd call "complete",
  17. but it's better than anything I've found.  And it includes a sample
  18. message catalog for the three commands that are included.
  19. --
  20. #!/bin/sh
  21. # shar:    Shell Archiver  (v1.29)
  22. #
  23. #    Run the following text with /bin/sh to create:
  24. #      LICENSE
  25. #      Makefile
  26. #      patchlevel.h
  27. #      gencat.c
  28. #      gencat.msg.En_US
  29. #      catgets.c
  30. #      l_catclose.c
  31. #      l_catgets.c
  32. #      l_catopen.c
  33. #      nl_types.h
  34. #
  35. sed 's/^X//' << 'SHAR_EOF' > LICENSE &&
  36. X(*
  37. XThis document is freely plagiarised from the 'Artistic Licence',
  38. Xdistributed as part of the Perl v4.0 kit by Larry Wall, which is
  39. Xavailable from most major archive sites.  I stole it from CrackLib.
  40. X
  41. X    @(#)LICENSE    3.1    20:07:28    02 Feb 1994
  42. X*)
  43. X
  44. XThis documents purpose is to state the conditions under which this
  45. XPackage (See definition below) viz: "NLS-LIB", the National Language
  46. XLibrary which is held in John Frederick Haugh, II, may be copied, such
  47. Xthat the copyright holder maintains some semblance of artistic control
  48. Xover the development of the package, while giving the users of the
  49. Xpackage the right to use and distribute the Package in a more-or-less
  50. Xcustomary fashion, plus the right to make reasonable modifications. 
  51. X
  52. XSo there.
  53. X
  54. X***************************************************************************
  55. X
  56. XDefinitions:
  57. X
  58. X
  59. XA "Package" refers to the collection of files distributed by the
  60. XCopyright Holder, and derivatives of that collection of files created
  61. Xthrough textual modification, or segments thereof. 
  62. X
  63. X"Standard Version" refers to such a Package if it has not been modified,
  64. Xor has been modified in accordance with the wishes of the Copyright
  65. XHolder.
  66. X
  67. X"Copyright Holder" is whoever is named in the copyright or copyrights
  68. Xfor the package.
  69. X
  70. X"You" is you, if you're thinking about copying or distributing this
  71. XPackage.
  72. X
  73. X"Reasonable copying fee" is whatever you can justify on the basis of
  74. Xmedia cost, duplication charges, time of people involved, and so on.
  75. X(You will not be required to justify it to the Copyright Holder, but
  76. Xonly to the computing community at large as a market that must bear the
  77. Xfee.)
  78. X
  79. X"Freely Available" means that no fee is charged for the item itself,
  80. Xthough there may be fees involved in handling the item.  It also means
  81. Xthat recipients of the item may redistribute it under the same
  82. Xconditions they received it.
  83. X
  84. X
  85. X1.  You may make and give away verbatim copies of the source form of the
  86. XStandard Version of this Package without restriction, provided that you
  87. Xduplicate all of the original copyright notices and associated
  88. Xdisclaimers.
  89. X
  90. X2.  You may apply bug fixes, portability fixes and other modifications
  91. Xderived from the Public Domain or from the Copyright Holder.  A Package
  92. Xmodified in such a way shall still be considered the Standard Version.
  93. X
  94. X3.  You may otherwise modify your copy of this Package in any way,
  95. Xprovided that you insert a prominent notice in each changed file stating
  96. Xhow and when AND WHY you changed that file, and provided that you do at
  97. Xleast ONE of the following:
  98. X
  99. Xa) place your modifications in the Public Domain or otherwise make them
  100. XFreely Available, such as by posting said modifications to Usenet or an
  101. Xequivalent medium, or placing the modifications on a major archive site
  102. Xsuch as uunet.uu.net, or by allowing the Copyright Holder to include
  103. Xyour modifications in the Standard Version of the Package.
  104. X
  105. Xb) use the modified Package only within your corporation or organization.
  106. X
  107. Xc) rename any non-standard executables so the names do not conflict with
  108. Xstandard executables, which must also be provided, and provide separate
  109. Xdocumentation for each non-standard executable that clearly documents
  110. Xhow it differs from the Standard Version.
  111. X
  112. Xd) make other distribution arrangements with the Copyright Holder.
  113. X
  114. X4.  You may distribute the programs of this Package in object code or
  115. Xexecutable form, provided that you do at least ONE of the following:
  116. X
  117. Xa) distribute a Standard Version of the executables and library files,
  118. Xtogether with instructions (in the manual page or equivalent) on where
  119. Xto get the Standard Version.
  120. X
  121. Xb) accompany the distribution with the machine-readable source of the
  122. XPackage with your modifications.
  123. X
  124. Xc) accompany any non-standard executables with their corresponding
  125. XStandard Version executables, giving the non-standard executables
  126. Xnon-standard names, and clearly documenting the differences in manual
  127. Xpages (or equivalent), together with instructions on where to get the
  128. XStandard Version.
  129. X
  130. Xd) make other distribution arrangements with the Copyright Holder.
  131. X
  132. X5.  You may charge a reasonable copying fee for any distribution of this
  133. XPackage.  You may charge any fee you choose for support of this Package. 
  134. XYOU MAY NOT CHARGE A FEE FOR THIS PACKAGE ITSELF.  However, you may
  135. Xdistribute this Package in aggregate with other (possibly commercial)
  136. Xprograms as part of a larger (possibly commercial) software distribution
  137. Xprovided that YOU DO NOT ADVERTISE this package as a product of your
  138. Xown. 
  139. X
  140. X6.  The name of the Copyright Holder may not be used to endorse or
  141. Xpromote products derived from this software without specific prior
  142. Xwritten permission.
  143. X
  144. X7.  THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
  145. XWARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  146. XMERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  147. X
  148. X                The End
  149. SHAR_EOF
  150. chmod 0644 LICENSE || echo "restore of LICENSE fails"
  151. sed 's/^X//' << 'SHAR_EOF' > Makefile &&
  152. X#
  153. X# Copyright 1994, John F. Haugh II
  154. X# An unpublished work.
  155. X# All rights reserved.
  156. X#
  157. X# Permission is granted to copy and create derivative works for any
  158. X# non-commercial purpose, provided this copyright notice is preserved
  159. X# in all copies of source code, or included in human readable form
  160. X# and conspicuously displayed on all copies of object code or
  161. X# distribution media.
  162. X#
  163. X# This software is provided on an AS-IS basis and the author makes
  164. X# no warrantee of any kind.  The "Artistic License" located in the
  165. X# file LICENSE contains complete licensing information.
  166. X#
  167. X#    %W%    %U%    %G%
  168. X
  169. XDEBUG = -g
  170. XOPTIM = -O
  171. XCFLAGS = $(DEBUG) $(OPTIM)
  172. XRANLIB = echo
  173. X
  174. XLANG = En_US
  175. X
  176. XFILES = LICENSE Makefile patchlevel.h \
  177. X    gencat.c gencat.msg.En_US catgets.c \
  178. X    l_catclose.c l_catgets.c l_catopen.c nl_types.h
  179. X
  180. Xall: gencat catgets dspcat libnls.a gencat.cat
  181. X
  182. Xgencat: gencat.o libnls.a
  183. X    cc $(DEBUG) -o gencat gencat.o libnls.a
  184. X
  185. Xcatgets: catgets.o libnls.a
  186. X    cc $(DEBUG) -o catgets catgets.o libnls.a
  187. X
  188. Xdspcat: dspcat.o libnls.a
  189. X    cc $(DEBUG) -o dspcat dspcat.o libnls.a
  190. X
  191. Xgencat.cat: gencat.msg.$(LANG)
  192. X    ./gencat gencat.cat gencat.msg.$(LANG)
  193. X
  194. Xlibnls.a(l_catclose.o): l_catclose.c nl_types.h
  195. Xlibnls.a(l_catopen.o): l_catopen.c nl_types.h
  196. Xlibnls.a(l_catgets.o): l_catgets.c nl_types.h
  197. X
  198. Xlibnls.a: \
  199. X    libnls.a(l_catclose.o) \
  200. X    libnls.a(l_catgets.o) \
  201. X    libnls.a(l_catopen.o)
  202. X    $(RANLIB) libnls.a
  203. X
  204. Xclean:
  205. X    rm -f *.o a.out core
  206. X
  207. Xclobber: clean
  208. X    rm -f catgets gencat libnls.a gencat.cat
  209. X
  210. Xshar: libnls.shar
  211. X
  212. Xlibnls.shar: $(FILES)
  213. X    shar $(SHARFLAGS) $(FILES) > libnls.shar
  214. SHAR_EOF
  215. chmod 0644 Makefile || echo "restore of Makefile fails"
  216. sed 's/^X//' << 'SHAR_EOF' > patchlevel.h &&
  217. X/*
  218. X * Copyright 1994, John F. Haugh II
  219. X * An unpublished work.
  220. X * All rights reserved.
  221. X *
  222. X * Permission is granted to copy and create derivative works for any
  223. X * non-commercial purpose, provided this copyright notice is preserved
  224. X * in all copies of source code, or included in human readable form
  225. X * and conspicuously displayed on all copies of object code or
  226. X * distribution media.
  227. X *
  228. X * This software is provided on an AS-IS basis and the author makes
  229. X * no warrantee of any kind.  The "Artistic License" located in the
  230. X * file LICENSE contains complete licensing information.
  231. X *
  232. X *    %W%    %U%    %G%
  233. X */
  234. X
  235. X#define    RELEASE        1
  236. X#define    PATCHLEVEL    0
  237. X#define    VERSION        "1.0.0"
  238. SHAR_EOF
  239. chmod 0644 patchlevel.h || echo "restore of patchlevel.h fails"
  240. sed 's/^X//' << 'SHAR_EOF' > gencat.c &&
  241. X/*
  242. X * Copyright 1994, John F. Haugh II
  243. X * All rights reserved.
  244. X *
  245. X * Permission is granted to copy and create derivative works for any
  246. X * non-commercial purpose, provided this copyright notice is preserved
  247. X * in all copies of source code, or included in human readable form
  248. X * and conspicuously displayed on all copies of object code or
  249. X * distribution media.
  250. X *
  251. X * This software is provided on an AS-IS basis and the author makes
  252. X * no warrantee of any kind.  The "Artistic License" located in the
  253. X * file LICENSE contains complete licensing information.
  254. X */
  255. X
  256. X#ifndef    lint
  257. Xstatic    char    sccsid[] = "%W%    %U%    %G%";
  258. X#endif
  259. X
  260. X#include <sys/types.h>
  261. X#include <stdlib.h>
  262. X#include <unistd.h>
  263. X#include <stdio.h>
  264. X#include <ctype.h>
  265. X#include <string.h>
  266. X
  267. X#include "nl_types.h"
  268. X
  269. Xnl_catd    catd;
  270. X#define    M(msg,def)    catgets (catd, 1, msg, def)
  271. X
  272. Xint    lineno;
  273. Xint    quotec;
  274. X
  275. Xchar    **messages[NL_SETMAX];
  276. X
  277. Xvoid
  278. Xinvalid (FILE * fp)
  279. X{
  280. X    int    c;
  281. X
  282. X    fprintf (stderr, M(3, "invalid input line %d\n"), lineno);
  283. X
  284. X    while ((c = getc (fp)) != '\n' && c != EOF)
  285. X        ;
  286. X}
  287. X
  288. Xint
  289. Xoctal (FILE * fp)
  290. X{
  291. X    int    c;
  292. X    int    c1, c2, c3;
  293. X
  294. X    c1 = getc (fp);
  295. X    c2 = getc (fp);
  296. X    c3 = getc (fp);
  297. X
  298. X    if (! (c1 >= '0' && c1 <= '7' &&
  299. X            c2 >= '0' && c2 <= '7' &&
  300. X            c3 >= '0' && c3 <= '7'))
  301. X        return EOF;
  302. X
  303. X    c = ((c1 - '0') << 6) | ((c2 - '0') << 3) | (c3 - '0');
  304. X    return c;
  305. X}
  306. X
  307. Xvoid
  308. Xcomment (FILE * fp)
  309. X{
  310. X    int    c;
  311. X
  312. X    while ((c = getc (fp)) != EOF && c != '\n')
  313. X        ;
  314. X}
  315. X
  316. Xmessage (nl_catd catd, FILE * fp, int set)
  317. X{
  318. X    int    c;
  319. X    int    i;
  320. X    enum    { line_begin,
  321. X        number,
  322. X        text_begin, text_mid, text_end,
  323. X        done
  324. X    } state = line_begin;
  325. X    int    quoted;
  326. X    char    msg_num[16];
  327. X    int    cur_msg;
  328. X    char    line[NL_TEXTMAX+2];
  329. X
  330. X    while (state != done) {
  331. X        if ((c = getc (fp)) == EOF) {
  332. X            if (state == text_mid) {
  333. X                state = done;
  334. X                continue;
  335. X            }
  336. X            invalid (fp);
  337. X            return;
  338. X        }
  339. X        if (state == line_begin) {
  340. X            if (c == EOF || ! isdigit (c)) {
  341. X                invalid (fp);
  342. X                return;
  343. X            }
  344. X            state = number;
  345. X            i = 1;
  346. X            msg_num[0] = c;
  347. X            continue;
  348. X        }
  349. X        if (state == number) {
  350. X            if (isdigit (c)) {
  351. X                if (i >= sizeof msg_num - 1) {
  352. X                    invalid (fp);
  353. X                    return;
  354. X                }
  355. X                msg_num[i++] = c;
  356. X                continue;
  357. X            }
  358. X            if (isspace (c)) {
  359. X                msg_num[i] = '\0';
  360. X                cur_msg = atoi (msg_num);
  361. X                if (cur_msg < 1 || cur_msg > NL_MSGMAX) {
  362. X                    invalid (fp);
  363. X                    return;
  364. X                }
  365. X                if (catd->nl_sets < set)
  366. X                    catd->nl_sets = set;
  367. X
  368. X                if (catd->nl_msgs[set-1] == 0) {
  369. X                    catd->nl_msgs[set-1] = (off_t *)
  370. X                        calloc (NL_MSGMAX,
  371. X                            sizeof (off_t));
  372. X                }
  373. X                if (catd->nl_nmsgs[set-1] < cur_msg)
  374. X                    catd->nl_nmsgs[set-1] = cur_msg;
  375. X
  376. X                /*
  377. X                 * Just a number?  Delete the message from
  378. X                 * the catalog.
  379. X                 */
  380. X
  381. X                if (c == '\n') {
  382. X                    if (messages[set-1][cur_msg-1]) {
  383. X                        free (messages[set-1][cur_msg-1]);
  384. X                        messages[set-1][cur_msg-1] = 0;
  385. X                    }
  386. X                    return;
  387. X                }
  388. X
  389. X                /*
  390. X                 * Message ID followed by whitespace starts
  391. X                 * a valid message.  Reset the buffer pointer
  392. X                 * to start collecting characters.
  393. X                 */
  394. X
  395. X                state = text_begin;
  396. X                i = 0;
  397. X                continue;
  398. X            }
  399. X
  400. X            /*
  401. X             * There must be whitespace after the number.
  402. X             */
  403. X
  404. X            invalid (fp);
  405. X            return;
  406. X        }
  407. X
  408. X        /*
  409. X         * At the beginning of a message a single "quote" character
  410. X         * is allowed.  If `c' is that character, discard it and
  411. X         * change state.  Otherwise, push the charcter back because
  412. X         * it is part of the actual message text.
  413. X         */
  414. X
  415. X        if (state == text_begin) {
  416. X
  417. X            /*
  418. X             * No characters at all?  This is an empty message.
  419. X             */
  420. X
  421. X            if (c == '\n') {
  422. X                ungetc (c, fp);
  423. X                state = text_end;
  424. X                continue;
  425. X            }
  426. X            if (c != quotec)
  427. X                ungetc (c, fp);
  428. X            else
  429. X                quoted = 1;
  430. X
  431. X            state = text_mid;
  432. X            continue;
  433. X        }
  434. X
  435. X        if (state == text_mid) {
  436. X            if (quoted && c == quotec) {
  437. X                if ((c = getc (fp)) == EOF || c == '\n') {
  438. X                    ungetc (c, fp);
  439. X                    state = text_end;
  440. X                    continue;
  441. X                } else {
  442. X                    ungetc (c, fp);
  443. X                    c = quotec;
  444. X                }
  445. X            }
  446. X            if (c == '\n') {
  447. X                ungetc (c, fp);
  448. X                state = text_end;
  449. X                continue;
  450. X            }
  451. X            if (c == '\\') {
  452. X                c = getc (fp);
  453. X                if (c == EOF) {
  454. X                    invalid (fp);
  455. X                    return;
  456. X                }
  457. X                if (c == '\n')
  458. X                    continue;
  459. X
  460. X                switch (c) {
  461. X                    case 'n': c = '\n'; break;
  462. X                    case 't': c = '\t'; break;
  463. X                    case 'v': c = '\v'; break;
  464. X                    case 'b': c = '\b'; break;
  465. X                    case 'r': c = '\r'; break;
  466. X                    case 'f': c = '\f'; break;
  467. X                    case '\\': c = '\\'; break;
  468. X                    default:
  469. X                        if (isdigit (c)) {
  470. X                            ungetc (c, fp);
  471. X                            c = octal (fp);
  472. X                        }
  473. X                        if (c == EOF) {
  474. X                            invalid (fp);
  475. X                            return;
  476. X                        }
  477. X                }
  478. X            }
  479. X            if (i < NL_TEXTMAX)
  480. X                line[i++] = c;
  481. X
  482. X            continue;
  483. X        }
  484. X
  485. X        if (state == text_end) {
  486. X            if (i < NL_TEXTMAX)
  487. X                line[i] = '\0';
  488. X
  489. X            state = done;
  490. X            continue;
  491. X        }
  492. X    }
  493. X    if (i >= NL_TEXTMAX) {
  494. X        invalid (fp);
  495. X        return;
  496. X    }
  497. X    line[i] = '\0';
  498. X
  499. X    if (messages[set-1] == (char **) 0) {
  500. X        messages[set-1] =
  501. X            (char **) malloc (sizeof (char *) * NL_MSGMAX);
  502. X        memset (messages[set-1], 0, sizeof (char *) * NL_MSGMAX);
  503. X    }
  504. X    if (messages[set-1][cur_msg-1])
  505. X        free (messages[set - 1][cur_msg - 1]);
  506. X
  507. X    messages[set - 1][cur_msg - 1] = strdup (line);
  508. X}
  509. X
  510. Xint
  511. Xload_catalog (nl_catd new_catd)
  512. X{
  513. X    int    i, j, k;
  514. X    int    c;
  515. X    nl_cat_header header;
  516. X    char    buf[NL_TEXTMAX+1];
  517. X
  518. X    if (fread (&header, sizeof header, 1, new_catd->nl_cat_fp) != 1)
  519. X        return -1;
  520. X
  521. X    if (header.nl_sets < 1 || header.nl_sets > NL_SETMAX)
  522. X        return -1;
  523. X
  524. X    new_catd->nl_sets = header.nl_sets;
  525. X    memcpy (new_catd->nl_nmsgs, header.nl_nmsgs, sizeof header.nl_nmsgs);
  526. X
  527. X    for (i = 0;i < NL_SETMAX;i++) {
  528. X        if (! (new_catd->nl_msgs[i] = (off_t *) calloc
  529. X                (NL_MSGMAX, sizeof (off_t)))) {
  530. X            fprintf (stderr, M(11, "no memory"));
  531. X            exit (1);
  532. X        }
  533. X        if (! (messages[i] = (char **) calloc
  534. X                (NL_MSGMAX, sizeof (char *)))) {
  535. X            fprintf (stderr, M(11, "no memory"));
  536. X            exit (1);
  537. X        }
  538. X        if (new_catd->nl_nmsgs[i] == 0)
  539. X            continue;
  540. X
  541. X        if (fread (new_catd->nl_msgs[i], sizeof (off_t),
  542. X            new_catd->nl_nmsgs[i], new_catd->nl_cat_fp) !=
  543. X                new_catd->nl_nmsgs[i])    
  544. X            return -1;
  545. X    }
  546. X    for (i = 0;i < new_catd->nl_sets;i++) {
  547. X        for (j = 0;j < new_catd->nl_nmsgs[i];j++) {
  548. X            for (k = 0;(c = getc (new_catd->nl_cat_fp)) &&
  549. X                    c != EOF && k < NL_TEXTMAX;)
  550. X                buf[k++] = c;
  551. X
  552. X            if (k >= NL_TEXTMAX)
  553. X                return -1;
  554. X
  555. X            buf[k] = '\0';
  556. X            if (! (messages[i][j] = strdup (buf))) {
  557. X                fprintf (stderr, M(11, "no memory"));
  558. X                exit (1);
  559. X            }
  560. X        }
  561. X    }
  562. X    return 0;
  563. X}
  564. X
  565. Xmain (int argc, char ** argv)
  566. X{
  567. X    int    i, j;
  568. X    int    c;
  569. X    int    created = 0;
  570. X    nl_catd    new_catd;
  571. X    nl_cat_header header;
  572. X    char    error[BUFSIZ];
  573. X    int    nerrors = 0;
  574. X    int    cur_set = NL_SETD;
  575. X    FILE    *input = 0;
  576. X    off_t    base;
  577. X
  578. X    catd = catopen ("gencat", 0);
  579. X
  580. X    if (argc < 3) {
  581. X        fprintf (stderr, M(1, "usage: gencat catfile msgfile ...\n"));
  582. X        exit (1);
  583. X    }
  584. X    if (! (new_catd = (nl_catd) malloc (sizeof *new_catd))) {
  585. X        perror (M(4, "gencat: can't create new catalog descriptor"));
  586. X        exit (1);
  587. X    }
  588. X    memset (new_catd, 0, sizeof *new_catd);
  589. X    memset (&header, 0, sizeof header);
  590. X
  591. X    /*
  592. X     * See if the file already exists.  If it doesn't we will be
  593. X     * creating it from scratch.
  594. X     */
  595. X
  596. X    if (access (argv[1], 0) == -1)
  597. X        created = 1;
  598. X
  599. X    /*
  600. X     * Try to open the message catalog.  If it exists, it will be
  601. X     * opened for read/update, if it doesn't we create a brand new
  602. X     * empty file.
  603. X     */
  604. X
  605. X    if (! (new_catd->nl_cat_fp = fopen (argv[1], created ? "w":"r+"))) {
  606. X        if (created)
  607. X            sprintf (error, M(6, "gencat: can't create catalog %s"),
  608. X                argv[1]);
  609. X        else
  610. X            sprintf (error, M(9, "gencat: can't open catalog %s"),
  611. X                argv[1]);
  612. X
  613. X        perror (error);
  614. X        exit (1);
  615. X    }
  616. X
  617. X    /*
  618. X     * Initialize the catalog descriptor to completely empty.  If
  619. X     * there was an existing catalog file, we're going to go load
  620. X     * it up in a second.
  621. X     */
  622. X
  623. X    new_catd->nl_sets = 0;
  624. X    for (i = 0;i < NL_SETMAX;i++) {
  625. X        new_catd->nl_nmsgs[i] = 0;
  626. X        new_catd->nl_msgs[i] = (off_t *) 0;
  627. X    }
  628. X    if (! created) {
  629. X        if (load_catalog (new_catd)) {
  630. X            fprintf (stderr, M(10, "invalid catalog file %s\n"),
  631. X                argv[1]);
  632. X            exit (1);
  633. X        }
  634. X    }
  635. X
  636. X    for (i = 2;i < argc;i++) {
  637. X        if (input && input != stdin) {
  638. X            fclose (input);
  639. X            input = 0;
  640. X        }
  641. X        if (strcmp (argv[i], "-") == 0) {
  642. X            input = stdin;
  643. X        } else if (! (input = fopen (argv[i], "r"))) {
  644. X            sprintf (error, M(7, "gencat: can't open %s"), argv[i]);
  645. X            perror (error);
  646. X            nerrors++;
  647. X            continue;
  648. X        }
  649. X        lineno = 0;
  650. X        if (argc > 3)
  651. X            printf ("%s:\n", argv[i]);
  652. X
  653. X        while ((c = getc (input)) != EOF) {
  654. X            lineno++;
  655. X            if (c != '$') {
  656. X                ungetc (c, input);
  657. X                message (new_catd, input,  cur_set);
  658. X                continue;
  659. X            }
  660. X            if ((c = getc (input)) == EOF)
  661. X                break;
  662. X
  663. X            if (c == ' ' || c == '\t' || c == '\n') {
  664. X                if (c != '\n')
  665. X                    comment (input);
  666. X
  667. X                continue;
  668. X            }
  669. X            if (c == 's') {
  670. X                int    new_set;
  671. X
  672. X                ungetc (c, input);
  673. X                if (fscanf (input, "set%*[     ]%d%*[^\n]",
  674. X                        &new_set) != 1) {
  675. X                    invalid (input);
  676. X                    nerrors++;
  677. X                    continue;
  678. X                }
  679. X                if (new_set < 1 || new_set > NL_SETMAX) {
  680. X                    invalid (input);
  681. X                    nerrors++;
  682. X                    continue;
  683. X                }
  684. X                getc (input);
  685. X                cur_set = new_set;
  686. X                continue;
  687. X            }
  688. X            if (c == 'd') {
  689. X                char    old_set;
  690. X
  691. X                ungetc (c, input);
  692. X                if (fscanf (input, "delset%*[     ]%d%*[^\n]",
  693. X                        &old_set) != 1) {
  694. X                    invalid (input);
  695. X                    nerrors++;
  696. X                    continue;
  697. X                }
  698. X                if (old_set < 1 || old_set >= NL_SETMAX) {
  699. X                    invalid (input);
  700. X                    nerrors++;
  701. X                    continue;
  702. X                }
  703. X                memset (new_catd->nl_msgs[old_set - 1], 0,
  704. X                    NL_MSGMAX * sizeof (off_t));
  705. X                new_catd->nl_nmsgs[old_set - 1] = 0;
  706. X                for (i = 0;i < NL_MSGMAX;i++) {
  707. X                    if (messages[old_set-1][i])
  708. X                        free (messages[old_set-1][i]);
  709. X
  710. X                    messages[old_set-1][i] = 0;
  711. X                }
  712. X                getc (input);
  713. X                continue;
  714. X            }
  715. X            if (c == 'q') {
  716. X                char    new_quotec;
  717. X
  718. X                ungetc (c, input);
  719. X                if (fscanf (input, "quote%*[     ]%c%*[^\n]\n",
  720. X                        &new_quotec) != 1) {
  721. X                    invalid (input);
  722. X                    nerrors++;
  723. X                    continue;
  724. X                }
  725. X                getc (input);
  726. X                quotec = new_quotec;
  727. X                continue;
  728. X            }
  729. X        }
  730. X    }
  731. X
  732. X    /*
  733. X     * There were some errors and they were already reported.  If we
  734. X     * created the message catalog go ahead and delete the file.
  735. X     */
  736. X
  737. X    if (nerrors) {
  738. X        if (created)
  739. X            (void) unlink (argv[1]);
  740. X
  741. X        exit (2);
  742. X    }
  743. X
  744. X    /*
  745. X     * Scan the in-core message catalog information to determine
  746. X     * how many sets were defined and how many messages are in each
  747. X     * set.  The information in the catalog descriptor right now
  748. X     * may be wrong as sets and messages may have been deleted.
  749. X     */
  750. X
  751. X    for (i = 0;i < NL_SETMAX;i++) {
  752. X
  753. X        /*
  754. X         * If there are no messages at all in the set, or there
  755. X         * never were, just say so and skip.
  756. X         */
  757. X
  758. X        if (new_catd->nl_msgs[i] == (off_t *) 0 ||
  759. X                new_catd->nl_nmsgs[i] == 0) {
  760. X            new_catd->nl_nmsgs[i] = 0;
  761. X            continue;
  762. X        }
  763. X
  764. X        /*
  765. X         * There must have been a message sometime in the past,
  766. X         * so set the count to zero and see what the highest
  767. X         * numbered one is now.
  768. X         */
  769. X
  770. X        new_catd->nl_nmsgs[i] = 0;
  771. X        for (j = 0;j < NL_MSGMAX;j++) {
  772. X            if (messages[i][j])
  773. X                new_catd->nl_nmsgs[i] = j + 1;
  774. X        }
  775. X
  776. X        /*
  777. X         * There weren't any?  The last one must have been
  778. X         * deleted, so we completely delete the set now by saying
  779. X         * it has no messages.
  780. X         */
  781. X
  782. X        if (new_catd->nl_nmsgs[i] == 0)
  783. X            continue;
  784. X
  785. X        /*
  786. X         * This set has at least one message, make it the highest
  787. X         * numbered set.
  788. X         */
  789. X
  790. X        new_catd->nl_sets = i + 1;
  791. X    }
  792. X    header.nl_sets = new_catd->nl_sets;
  793. X    memcpy (header.nl_nmsgs, new_catd->nl_nmsgs,
  794. X        new_catd->nl_sets * sizeof (off_t));
  795. X
  796. X    base = sizeof header;
  797. X    for (i = 0;i < new_catd->nl_sets;i++)
  798. X        base += new_catd->nl_nmsgs[i] * sizeof (off_t);
  799. X
  800. X    for (i = 0;i < new_catd->nl_sets;i++) {
  801. X        for (j = 0;j < new_catd->nl_nmsgs[i];j++) {
  802. X            if (messages[i][j] == (char *) 0) {
  803. X                new_catd->nl_msgs[i][j] = 0;
  804. X                continue;
  805. X            }
  806. X            new_catd->nl_msgs[i][j] = base;
  807. X            base += strlen (messages[i][j]) + 1;
  808. X        }
  809. X    }
  810. X    if (! created) {
  811. X        if (! (new_catd->nl_cat_fp = fopen (argv[1], "w"))) {
  812. X            sprintf (error, M(6, "gencat: can't create catalog %s"),
  813. X                argv[1]);
  814. X            perror (error);
  815. X            exit (1);
  816. X        }
  817. X    }
  818. X    if (fwrite (&header, sizeof header, 1, new_catd->nl_cat_fp) != 1) {
  819. X        sprintf (error, M(8, "gencat: can't write to %s"), argv[1]);
  820. X        perror (error);
  821. X        exit (1);
  822. X    }
  823. X    for (i = 0;i < new_catd->nl_sets;i++) {
  824. X        if (new_catd->nl_nmsgs[i] == 0)
  825. X            continue;
  826. X
  827. X        if (fwrite (new_catd->nl_msgs[i], sizeof (off_t),
  828. X            new_catd->nl_nmsgs[i], new_catd->nl_cat_fp) !=
  829. X                new_catd->nl_nmsgs[i]) {
  830. X            sprintf (error,
  831. X                M(8, "gencat: can't write to %s"), argv[1]);
  832. X            perror (error);
  833. X            exit (1);
  834. X        }
  835. X    }
  836. X    for (i = 0;i < new_catd->nl_sets;i++) {
  837. X        if (new_catd->nl_msgs[i] == (off_t *) 0)
  838. X            continue;
  839. X
  840. X        for (j = 0;j < new_catd->nl_nmsgs[i];j++) {
  841. X            if (messages[i][j] == (char *) 0)
  842. X                continue;
  843. X
  844. X            if (fwrite (messages[i][j],
  845. X                strlen (messages[i][j]) + 1, 1,
  846. X                    new_catd->nl_cat_fp) != 1) {
  847. X                sprintf (error,
  848. X                    M(8, "gencat: can't write to %s"),
  849. X                    argv[1]);
  850. X                perror (error);
  851. X                exit (1);
  852. X            }
  853. X        }
  854. X    }
  855. X    exit (0);
  856. X}
  857. SHAR_EOF
  858. chmod 0644 gencat.c || echo "restore of gencat.c fails"
  859. sed 's/^X//' << 'SHAR_EOF' > gencat.msg.En_US &&
  860. X$quote "
  861. X$
  862. X$ message catalog for "gencat"
  863. X$
  864. X$set 1
  865. X1 Usage: gencat catfile msgfile ...\n
  866. X2 gencat: Unable to open the file %s\n
  867. X3 Invalid line in input file, line %d\n
  868. X4 gencat: Unable to create new message catalog\n
  869. X5 gencat: Unable to create temporary file\n
  870. X6 gencat: Unable to create message catalog file %s
  871. X7 gencat: Unable to open message file %s
  872. X8 gencat: Unable to write to message catalog file %s
  873. X9 gencat: Unable to open message catalog file %s
  874. X10 gencat: The file %s is not a valid message catalog\n
  875. X11 gencat: Out of memory loading message catalog
  876. X$
  877. X$ message catalog for "catgets"
  878. X$
  879. X$set 2
  880. X1 Usage: catgets catalog set msg default\n
  881. X$
  882. X$ message catalog for "dspcat"
  883. X$
  884. X$set 3
  885. X1 Usage: dspcat catalog [ set [ msg ] ]\n
  886. X2 dspcat: Unable to open message catalog file %s\n
  887. X3 dspcat: "%s" is an invalid set number.\n
  888. X4 dspcat: "%s" is an invalid message number.\n
  889. SHAR_EOF
  890. chmod 0644 gencat.msg.En_US || echo "restore of gencat.msg.En_US fails"
  891. sed 's/^X//' << 'SHAR_EOF' > catgets.c &&
  892. X/*
  893. X * Copyright 1994, John F. Haugh II
  894. X * All rights reserved.
  895. X *
  896. X * Permission is granted to copy and create derivative works for any
  897. X * non-commercial purpose, provided this copyright notice is preserved
  898. X * in all copies of source code, or included in human readable form
  899. X * and conspicuously displayed on all copies of object code or
  900. X * distribution media.
  901. X *
  902. X * This software is provided on an AS-IS basis and the author makes
  903. X * no warrantee of any kind.  The "Artistic License" located in the
  904. X * file LICENSE contains complete licensing information.
  905. X */
  906. X
  907. X#ifndef lint
  908. Xstatic char sccsid[] = "%W%    %U%    %G%";
  909. X#endif
  910. X
  911. X#include <stdio.h>
  912. X#include "nl_types.h"
  913. X
  914. Xnl_catd    catd;
  915. X#define    M(msg,def)    catgets (catd, 2, msg, def)
  916. X
  917. Xmain (int argc, char ** argv)
  918. X{
  919. X    nl_catd    cmd_catd;
  920. X    char    *msg;
  921. X
  922. X    catd = catopen ("gencat", 0);
  923. X
  924. X    if (argc < 5) {
  925. X        fprintf (stderr,
  926. X            M(1, "usage: catgets catalog set msg default\n"));
  927. X        exit (1);
  928. X    }
  929. X    cmd_catd = catopen (argv[1], 0);
  930. X    if (msg = catgets (cmd_catd, atoi (argv[2]), atoi (argv[3]), argv[4]))
  931. X        write (1, msg, strlen (msg));
  932. X    else
  933. X        write (1, argv[4], strlen (argv[4]));
  934. X
  935. X    exit (1);
  936. X}
  937. SHAR_EOF
  938. chmod 0644 catgets.c || echo "restore of catgets.c fails"
  939. sed 's/^X//' << 'SHAR_EOF' > l_catclose.c &&
  940. X/*
  941. X * Copyright 1994, John F. Haugh II
  942. X * All rights reserved.
  943. X *
  944. X * Permission is granted to copy and create derivative works for any
  945. X * non-commercial purpose, provided this copyright notice is preserved
  946. X * in all copies of source code, or included in human readable form
  947. X * and conspicuously displayed on all copies of object code or
  948. X * distribution media.
  949. X *
  950. X * This software is provided on an AS-IS basis and the author makes
  951. X * no warrantee of any kind.  The "Artistic License" located in the
  952. X * file LICENSE contains complete licensing information.
  953. X */
  954. X
  955. X#ifndef    lint
  956. Xstatic    char    sccsid[] = "%W%    %U%    %G%";
  957. X#endif
  958. X
  959. X#include <sys/types.h>
  960. X#include <stdio.h>
  961. X#include "nl_types.h"
  962. X
  963. Xint
  964. Xcatclose (nl_catd catd)
  965. X{
  966. X    int    i;
  967. X
  968. X    if (catd == (nl_catd) -1)
  969. X        return -1;
  970. X
  971. X    fclose (catd->nl_cat_fp);
  972. X
  973. X    for (i = 0;i <= catd->nl_sets;i++)
  974. X        if (catd->nl_msgs[i])
  975. X            free (catd->nl_nmsgs);
  976. X
  977. X    free (catd);
  978. X    return 0;
  979. X}
  980. SHAR_EOF
  981. chmod 0644 l_catclose.c || echo "restore of l_catclose.c fails"
  982. sed 's/^X//' << 'SHAR_EOF' > l_catgets.c &&
  983. X/*
  984. X * Copyright 1994, John F. Haugh II
  985. X * All rights reserved.
  986. X *
  987. X * Permission is granted to copy and create derivative works for any
  988. X * non-commercial purpose, provided this copyright notice is preserved
  989. X * in all copies of source code, or included in human readable form
  990. X * and conspicuously displayed on all copies of object code or
  991. X * distribution media.
  992. X *
  993. X * This software is provided on an AS-IS basis and the author makes
  994. X * no warrantee of any kind.  The "Artistic License" located in the
  995. X * file LICENSE contains complete licensing information.
  996. X */
  997. X
  998. X#ifndef    lint
  999. Xstatic    char    sccsid[] = "%W%    %U%    %G%";
  1000. X#endif
  1001. X
  1002. X#include <sys/types.h>
  1003. X#include <stdio.h>
  1004. X#include "nl_types.h"
  1005. X
  1006. Xchar *
  1007. Xcatgets (nl_catd catd, int set_num, int msg_num, char * def_msg)
  1008. X{
  1009. X    static    char    buf[NL_TEXTMAX];
  1010. X    int    i;
  1011. X    int    c;
  1012. X
  1013. X    if (catd == (nl_catd) -1)
  1014. X        return def_msg;
  1015. X
  1016. X    if (set_num < 1 || set_num > catd->nl_sets)
  1017. X        return def_msg;
  1018. X
  1019. X    if (msg_num < 1 || msg_num > catd->nl_nmsgs[set_num-1])
  1020. X        return def_msg;
  1021. X
  1022. X    if (catd->nl_msgs[set_num-1][msg_num-1] == (off_t) 0)
  1023. X        return def_msg;
  1024. X
  1025. X    if (fseek (catd->nl_cat_fp, catd->nl_msgs[set_num-1][msg_num-1], 0))
  1026. X        return def_msg;
  1027. X
  1028. X    for (i = 0;i < (NL_TEXTMAX-1);i++) {
  1029. X        if ((c = getc (catd->nl_cat_fp)) == '\0' || c == EOF)
  1030. X            break;
  1031. X
  1032. X        buf[i] = c;
  1033. X    }
  1034. X    buf[i++] = '\0';
  1035. X    return buf;
  1036. X}
  1037. SHAR_EOF
  1038. chmod 0644 l_catgets.c || echo "restore of l_catgets.c fails"
  1039. sed 's/^X//' << 'SHAR_EOF' > l_catopen.c &&
  1040. X/*
  1041. X * Copyright 1994, John F. Haugh II
  1042. X * All rights reserved.
  1043. X *
  1044. X * Permission is granted to copy and create derivative works for any
  1045. X * non-commercial purpose, provided this copyright notice is preserved
  1046. X * in all copies of source code, or included in human readable form
  1047. X * and conspicuously displayed on all copies of object code or
  1048. X * distribution media.
  1049. X *
  1050. X * This software is provided on an AS-IS basis and the author makes
  1051. X * no warrantee of any kind.  The "Artistic License" located in the
  1052. X * file LICENSE contains complete licensing information.
  1053. X */
  1054. X
  1055. X#ifndef    lint
  1056. Xstatic    char    sccsid[] = "%W%    %U%    %G%";
  1057. X#endif
  1058. X
  1059. X#include <limits.h>
  1060. X#include <unistd.h>
  1061. X#include <stdlib.h>
  1062. X#include <string.h>
  1063. X#include <stdio.h>
  1064. X
  1065. X#undef    NL_MSGMAX
  1066. X#undef    NL_SETMAX
  1067. X#undef    NL_TEXTMAX
  1068. X
  1069. X#include "nl_types.h"
  1070. X
  1071. Xstatic    char    lang_var[32];
  1072. Xstatic    char    language[16];
  1073. Xstatic    char    territory[16];
  1074. Xstatic    char    codeset[16];
  1075. X
  1076. Xstatic void
  1077. Xget_lang_var ()
  1078. X{
  1079. X    char    *lang;
  1080. X
  1081. X    if (! (lang = getenv ("LANG")))
  1082. X        lang = "C";
  1083. X
  1084. X    strncpy (lang_var, lang, sizeof lang_var);
  1085. X
  1086. X    switch (sscanf (lang_var, "%16[^_]_%16[^.].%16s",
  1087. X            language, territory, codeset)) {
  1088. X        default:
  1089. X        case 0:
  1090. X            language[0] = '\0';
  1091. X        case 1:
  1092. X            territory[0] = '\0';
  1093. X        case 2:
  1094. X            codeset[0] = '\0';
  1095. X        case 3:
  1096. X            return;
  1097. X    }
  1098. X}
  1099. X
  1100. Xstatic int
  1101. Xget_cat_name (char * file, const char * path, const char * name)
  1102. X{
  1103. X    char    *begin, *end;
  1104. X    char    *cp1, *cp2;
  1105. X    char    dummy[BUFSIZ];
  1106. X
  1107. X    strncpy (dummy, path, sizeof dummy - 1);
  1108. X    dummy[BUFSIZ-1] = '\0';
  1109. X    file[0] = '\0';
  1110. X
  1111. X    for (begin = dummy;begin;begin = end) {
  1112. X        if (end = strchr (begin, ':'))
  1113. X            *end++ = '\0';
  1114. X
  1115. X        for (cp1 = begin, cp2 = file;*cp1;) {
  1116. X            if (*cp1 != '%') {
  1117. X                *cp2++ = *cp1++;
  1118. X                continue;
  1119. X            }
  1120. X            switch (*++cp1) {
  1121. X                default:
  1122. X                case '%':
  1123. X                    *cp2++ = *cp1++;
  1124. X                    continue;
  1125. X                case 'N':
  1126. X                    strcpy (cp2, name);
  1127. X                    cp1++;
  1128. X                    cp2 += strlen (name);
  1129. X                    continue;
  1130. X                case 'L':
  1131. X                    strcpy (cp2, lang_var);
  1132. X                    cp1++;
  1133. X                    cp2 += strlen (lang_var);
  1134. X                    continue;
  1135. X                case 'l':
  1136. X                    strcpy (cp2, language);
  1137. X                    cp1++;
  1138. X                    cp2 += strlen (language);
  1139. X                    continue;
  1140. X                case 't':
  1141. X                    strcpy (cp2, territory);
  1142. X                    cp1++;
  1143. X                    cp2 += strlen (territory);
  1144. X                    continue;
  1145. X                case 'c':
  1146. X                    strcpy (cp2, codeset);
  1147. X                    cp1++;
  1148. X                    cp2 += strlen (codeset);
  1149. X                    continue;
  1150. X            }
  1151. X        }
  1152. X        *cp2 = '\0';
  1153. X
  1154. X        if (access (file, 0) == 0)
  1155. X            return 0;
  1156. X    }
  1157. X    return -1;
  1158. X}
  1159. X
  1160. Xnl_catd
  1161. Xcatopen (const char * name, int oflag)
  1162. X{
  1163. X    char    *nlspath;
  1164. X    char    catalog[PATH_MAX];
  1165. X    int    i;
  1166. X    nl_catd catd;
  1167. X    nl_cat_header header;
  1168. X
  1169. X    if (! (nlspath = getenv ("NLSPATH")))
  1170. X        nlspath = "/usr/lib/nls/%L/%N.cat";
  1171. X
  1172. X    get_lang_var ();
  1173. X
  1174. X    if (strcmp (language, "C") == 0)
  1175. X        return (nl_catd) -1;
  1176. X
  1177. X    if (get_cat_name (catalog, nlspath, name))
  1178. X        return (nl_catd) -1;
  1179. X
  1180. X    if (! (catd = (nl_catd) malloc (sizeof *catd)))
  1181. X        return (nl_catd) -1;
  1182. X
  1183. X    if (! (catd->nl_cat_fp = fopen (catalog, "r"))) {
  1184. X        free (catd);
  1185. X        return (nl_catd) -1;
  1186. X    }
  1187. X    if (fread (&header, sizeof header, 1, catd->nl_cat_fp) != 1) {
  1188. X        fclose (catd->nl_cat_fp);
  1189. X        free (catd);
  1190. X        return (nl_catd) -1;
  1191. X    }
  1192. X    catd->nl_sets = header.nl_sets;
  1193. X    for (i = 0;i < catd->nl_sets;i++)
  1194. X        catd->nl_msgs[i] = (off_t *) 0;
  1195. X
  1196. X    for (i = 0;i < header.nl_sets;i++) {
  1197. X        catd->nl_nmsgs[i] = header.nl_nmsgs[i];
  1198. X
  1199. X        if (catd->nl_nmsgs[i] == 0) {
  1200. X            catd->nl_msgs[i] = (off_t *) 0;
  1201. X            continue;
  1202. X        }
  1203. X        if (! (catd->nl_msgs[i] = (off_t *)
  1204. X                malloc (sizeof (off_t) * header.nl_nmsgs[i])))
  1205. X            goto fail;
  1206. X        if (fread (catd->nl_msgs[i], sizeof (off_t) *
  1207. X                header.nl_nmsgs[i], 1, catd->nl_cat_fp) != 1)
  1208. X            goto fail;
  1209. X    }
  1210. X    return catd;
  1211. X
  1212. Xfail:
  1213. X    fclose (catd->nl_cat_fp);
  1214. X
  1215. X    for (i = 0;i <= catd->nl_sets;i++)
  1216. X        if (catd->nl_msgs[i])
  1217. X            free (catd->nl_nmsgs);
  1218. X
  1219. X    free (catd);
  1220. X    return (nl_catd) -1;
  1221. X}
  1222. SHAR_EOF
  1223. chmod 0644 l_catopen.c || echo "restore of l_catopen.c fails"
  1224. sed 's/^X//' << 'SHAR_EOF' > nl_types.h &&
  1225. X/*
  1226. X * Copyright 1994, John F. Haugh II
  1227. X * All rights reserved.
  1228. X *
  1229. X * Permission is granted to copy and create derivative works for any
  1230. X * non-commercial purpose, provided this copyright notice is preserved
  1231. X * in all copies of source code, or included in human readable form
  1232. X * and conspicuously displayed on all copies of object code or
  1233. X * distribution media.
  1234. X *
  1235. X * This software is provided on an AS-IS basis and the author makes
  1236. X * no warrantee of any kind.  The "Artistic License" located in the
  1237. X * file LICENSE contains complete licensing information.
  1238. X *
  1239. X *    %W%    %U%    %G%
  1240. X */
  1241. X
  1242. X#define    NL_MSGMAX    256
  1243. X#define    NL_SETD        1
  1244. X#define    NL_SETMAX    16
  1245. X#define    NL_TEXTMAX    1024
  1246. X
  1247. Xtypedef struct {
  1248. X    FILE    *nl_cat_fp;
  1249. X    int    nl_sets;
  1250. X    int    nl_nmsgs[NL_SETMAX];
  1251. X    off_t    *nl_msgs[NL_SETMAX];
  1252. X} * nl_catd;
  1253. X
  1254. Xtypedef struct {
  1255. X    int    nl_sets;
  1256. X    int    nl_nmsgs[NL_SETMAX];
  1257. X} nl_cat_header;
  1258. X
  1259. Xnl_catd catopen (const char *, int);
  1260. Xint catclose (nl_catd);
  1261. Xchar *catgets (nl_catd, int, int, char *);
  1262. SHAR_EOF
  1263. chmod 0644 nl_types.h || echo "restore of nl_types.h fails"
  1264. exit 0
  1265. -- 
  1266. John F. Haugh II  [ NRA-ILA ] [ Kill Barney ] !'s: ...!cs.utexas.edu!rpp386!jfh
  1267. Ma Bell: (512) 251-2151 [GOP][DoF #17][PADI][ENTJ]   @'s: jfh@rpp386.cactus.org
  1268.  There are three documents that run my life: The King James Bible, the United
  1269.  States Constitution, and the UNIX System V Release 4 Programmer's Reference.
  1270.  
  1271.  
  1272.